package de.jmda.gen.java.impl;

import java.lang.annotation.Annotation;
import java.util.List;

import javax.lang.model.element.Name;
import javax.validation.constraints.NotNull;

import de.jmda.gen.Generator;
import de.jmda.gen.GeneratorException;
import de.jmda.gen.java.ClassGenerator;
import de.jmda.gen.java.FieldGenerator;
import de.jmda.gen.java.InstanceFieldGenerator;
import de.jmda.gen.java.InstanceMethodGenerator;
import de.jmda.gen.java.MethodGenerator;
import de.jmda.gen.java.StaticFieldGenerator;
import de.jmda.gen.java.StaticMethodGenerator;

/**
 * @author roger.jmda@gmail.com
 */
public class DefaultClassGenerator
		extends DefaultCompilationUnitTypeGenerator
		implements ClassGenerator
{
	private MainMethodGenerator mainMethodGenerator;

	public StaticMethodGenerator getMainMethodGenerator()
	{
		return mainMethodGenerator;
	}

	public void setMainMethodGenerator(MainMethodGenerator generator)
	{
		this.mainMethodGenerator = generator;
	}

	@Override
  public List<Generator> getGeneratorComponents()
  {
		if (mainMethodGenerator != null)
		{
      List<StaticMethodGenerator> generators =
      		 getCompilationUnitTypeDeclarationGenerator()
      		.getDeclaredTypeGenerator()
      		.getTypeBodyGenerator()
      		.demandStaticPartsGenerator()
      		.demandPrimaryStaticPartGenerator()
      		.demandStaticMethodDeclarationsGenerator()
      		.getGenerators();

      if (false == generators.contains(mainMethodGenerator))
      {
      	generators.add(mainMethodGenerator);
      }
		}

		return super.getGeneratorComponents();
  }

	@Override
  public void setClassName(@NotNull String classname)
  {
		setCompilationUnitTypeName(classname);
  }

	@Override
  public void setClassName(@NotNull Name classname)
  {
		setClassName(classname.toString());
  }

	@Override
	@NotNull
  public String getClassName() throws GeneratorException
  {
	  return getCompilationUnitTypeName();
  }

	@Override
  public void setExtendsClause(String extendsClause)
  {
		getCompilationUnitTypeDeclarationGenerator().getDeclaredTypeGenerator()
		                                            .demandExtendsClauseGenerator()
		                                            .setExtendsClause(extendsClause);
  }

	@Override
  public void setExtendsClause(StringBuffer extendsClause)
  {
		getCompilationUnitTypeDeclarationGenerator().getDeclaredTypeGenerator()
		                                            .demandExtendsClauseGenerator()
		                                            .setExtendsClause(extendsClause);
  }

	@Override
  public void setExtendsClause(Class<?> superClass)
  {
		getCompilationUnitTypeDeclarationGenerator().getDeclaredTypeGenerator()
		                                            .demandExtendsClauseGenerator()
		                                            .setExtendsClause(superClass);
  }

	@Override
  public StringBuffer getExtendsClause() throws GeneratorException
  {
		return
				getCompilationUnitTypeDeclarationGenerator()
						.getDeclaredTypeGenerator()
						.demandExtendsClauseGenerator()
						.getExtendsClause();

  }

	@Override
  public void setImplementsClause(String implementsClause)
  {
		getCompilationUnitTypeDeclarationGenerator().getDeclaredTypeGenerator()
		                                            .demandImplementsClauseGenerator()
		                                            .setImplementsClause(implementsClause);
  }

	@Override
  public StringBuffer getImplementsClause() throws GeneratorException
  {
		return
				getCompilationUnitTypeDeclarationGenerator()
						.getDeclaredTypeGenerator()
						.demandImplementsClauseGenerator()
						.getImplementsClause();

  }

	@Override
  public void setMainMethod(String methodBody)
  {
		if (mainMethodGenerator == null)
		{
			mainMethodGenerator = new MainMethodGenerator(methodBody);
		}
		else
		{
			mainMethodGenerator.getDeclaredMethodGenerator()
			                   .setMethodBody(methodBody);
		}
  }

	@Override
  public String getMainMethod() throws GeneratorException
  {
		// TODO make null safe
	  return mainMethodGenerator.generate().toString();
  }

	@Override
  public void addAnnotation(
  		Class<? extends Annotation> annotation, StringBuffer parameters)
  {
		getCompilationUnitTypeDeclarationGenerator()
				.demandAnnotationStatementsGenerator()
				.getAnnotationStatementGenerators()
				.add(new DefaultAnnotationStatementGenerator(annotation, parameters));
  }

	@Override
  public void addMethodGenerator(MethodGenerator generator)
  {
		// TODO use visitor pattern
		if (generator instanceof InstanceMethodGenerator)
		{
			addMethodGenerator((InstanceMethodGenerator) generator);
		}
		else if (generator instanceof StaticMethodGenerator)
		{
			addMethodGenerator((StaticMethodGenerator) generator);
		}
		else
		{
			throw new UnsupportedOperationException(
					"unexpected type: " + generator.getClass());
		}
  }

	@Override
  public void addMethodGenerator(InstanceMethodGenerator generator)
  {
		getCompilationUnitTypeDeclarationGenerator()
    		.getDeclaredTypeGenerator()
    		.getTypeBodyGenerator()
    		.demandInstanceMethodDeclarationsGenerator().add(generator);
  }

	@Override
  public void addMethodGenerator(StaticMethodGenerator generator)
  {
		getCompilationUnitTypeDeclarationGenerator()
    		.getDeclaredTypeGenerator()
    		.getTypeBodyGenerator()
    		.demandStaticPartsGenerator()
    		.demandPrimaryStaticPartGenerator()
    		.demandStaticMethodDeclarationsGenerator().add(generator);
  }

	@Override
  public void addFieldGenerator(FieldGenerator generator)
  {
		// TODO use visitor pattern
		if (generator instanceof InstanceFieldGenerator)
		{
			addFieldGenerator((InstanceFieldGenerator) generator);
		}
		else if (generator instanceof StaticFieldGenerator)
		{
			addFieldGenerator((StaticFieldGenerator) generator);
		}
		else
		{
			throw new UnsupportedOperationException(
					"unexpected type: " + generator.getClass());
		}
  }

	@Override
  public void addFieldGenerator(
  		InstanceFieldGenerator generator)
  {
		getCompilationUnitTypeDeclarationGenerator()
				.getDeclaredTypeGenerator()
				.getTypeBodyGenerator()
				.demandInstanceFieldDeclarationsGenerator().add(generator);
  }

	@Override
  public void addFieldGenerator(
  		StaticFieldGenerator generator)
  {
		getCompilationUnitTypeDeclarationGenerator()
				.getDeclaredTypeGenerator()
				.getTypeBodyGenerator()
				.demandStaticPartsGenerator()
				.demandPrimaryStaticPartGenerator()
				.demandStaticFieldDeclarationsGenerator().add(generator);
  }

	@Override
  public boolean isAbstract()
  {
		return
				getCompilationUnitTypeDeclarationGenerator()
						.getDeclaredTypeGenerator()
						.demandModifiersGenerator()
						.isAbstract();
  }

	@Override
  public void setAbstract(boolean isAbstract)
  {
		getCompilationUnitTypeDeclarationGenerator()
				.getDeclaredTypeGenerator()
				.demandModifiersGenerator()
				.setAbstract(isAbstract);
  }
}